//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "ProcessBindingFASTAProfile.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>

#include <vector>
#include <algorithm>

#include <iostream>
#include <fstream>
#include <zlib.h>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHTEXT 1000
#define LENGTHLINE 100000
#define ITERATIONS 10
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace DomainSpace {
  
  bool SameLigand (TNode <String>* ligand, void* ref) {

    return (!strcmp(ligand->Info()->Out(), ((String*)ref)->Out()))?true:false;

  }
  
  bool EqualPDB (TNode <String>* pdb, void* ref) {

    return (!strncmp(pdb->Info()->Out(), ((String*)ref)->Out(), 4))?true:false;

  }
  
  bool EqualPDBChain (TNode <String>* pdb, void* ref) {

    return (!strncmp(pdb->Info()->Out(), ((String*)ref)->Out(), 5))?true:false;

  }
  
  bool DomainFromPDB (TNode <BindingInfo>* bindingInfo, void* ref) {

    return (!strncmp(bindingInfo->Info()->Domain()->Out(), ((String*)ref)->Out(), 5))?true:false;

  }
  
  bool EqualLigand (TNode <LigandDomainNumber>* ligand, void* ref) {
    
    LigandNearResidues* ligandRef = (LigandNearResidues*)ref;

    return ((!strcmp(ligand->Info()->name->Out(), ligandRef->LigandName()->Out())) && (ligand->Info()->number == ligandRef->LigandNumber()))?true:false;

  }
  
  bool DescendentFreqLigand(LigandDomainNumber* ligand, void* ref) {

    return (ligand->number > ((LigandDomainNumber*)ref)->number)?true:false;

  }
  
  bool AscendentDomainCode(BindingInfo* bindingInfo, void* ref) {

    return (strcmp(bindingInfo->CathCode()->Out(), ((BindingInfo*)ref)->CathCode()->Out()) < 0)?true:false;

  }
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessBindingFASTAProfile::ProcessBindingFASTAProfile () {
  
  this->filenameBindingProfile  = new String ();
  this->filenameListLigands     = new String ();
  this->bindingProfiles         = new TListE <BindingInfo> ();
  this->ligands                 = new TListE <String> ();
  this->filenameOut             = new String ();
  this->toString                = new String ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessBindingFASTAProfile::ProcessBindingFASTAProfile (const ProcessBindingFASTAProfile& processBindingFASTAProfile) {
  
  this->filenameBindingProfile  = new String (processBindingFASTAProfile.filenameBindingProfile);
  this->filenameListLigands     = new String (processBindingFASTAProfile.filenameListLigands);
  this->bindingProfiles         = new TListE <BindingInfo> (processBindingFASTAProfile.bindingProfiles);
  this->ligands                 = new TListE <String> (processBindingFASTAProfile.ligands);
  this->filenameOut             = new String (processBindingFASTAProfile.filenameOut);
  this->toString                = new String ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessBindingFASTAProfile::ProcessBindingFASTAProfile (const ProcessBindingFASTAProfile* processBindingFASTAProfile) {
  
  this->filenameBindingProfile  = new String (processBindingFASTAProfile->filenameBindingProfile);
  this->filenameListLigands     = new String (processBindingFASTAProfile->filenameListLigands);
  this->bindingProfiles         = new TListE <BindingInfo> (processBindingFASTAProfile->bindingProfiles);
  this->ligands                 = new TListE <String> (processBindingFASTAProfile->ligands);
  this->filenameOut             = new String (processBindingFASTAProfile->filenameOut);
  this->toString                = new String ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessBindingFASTAProfile::~ProcessBindingFASTAProfile () {
  
  if (this->filenameBindingProfile) delete this->filenameBindingProfile;
  if (this->filenameListLigands)    delete this->filenameListLigands;
  if (this->bindingProfiles)        delete this->bindingProfiles;
  if (this->ligands)                delete this->ligands;
  if (this->filenameOut)            delete this->filenameOut;
  if (this->toString)               delete this->toString;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessBindingFASTAProfile::FilenameBindingProfile (String* filenameBindingProfile) {
  
  if (filenameBindingProfile) this->filenameBindingProfile->In(filenameBindingProfile);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessBindingFASTAProfile::FilenameListLigands (String* filenameListLigands) {
  
  if (filenameListLigands) this->filenameListLigands->In(filenameListLigands);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessBindingFASTAProfile::BindingProfiles (TListE <BindingInfo>* bindingProfiles) {
  
  if (bindingProfiles) *(this->bindingProfiles) = *(bindingProfiles);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessBindingFASTAProfile::Ligands (TListE <String>* ligands) {
  
  if (ligands) *(this->ligands) = *(ligands);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessBindingFASTAProfile::FilenameOut (String* filenameOut) {
  
  if (filenameOut) this->filenameOut->In(filenameOut);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ProcessBindingFASTAProfile::FilenameBindingProfile (void) {
  
  return this->filenameBindingProfile;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ProcessBindingFASTAProfile::FilenameListLigands (void) {
  
  return this->filenameListLigands;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <BindingInfo>* ProcessBindingFASTAProfile::BindingProfiles (void) {
  
  return this->bindingProfiles;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* ProcessBindingFASTAProfile::Ligands (void) {
  
  return this->ligands;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ProcessBindingFASTAProfile::FilenameOut (void) {
  
  return this->filenameOut;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::LoadData (void) {

  if (!this->filenameBindingProfile || !this->filenameBindingProfile->Length() ||
      !this->filenameListLigands    || !this->filenameListLigands->Length()    ||
      !this->bindingProfiles)
    return false;

  this->bindingProfiles->Clear();
  
  bool isGZFile           = (this->filenameBindingProfile->Contain("gz"))?1:0;
  bool isGZFileLigandList = (this->filenameListLigands->Contain("gz"))?1:0;

  fstream fileIn, fileLigandList;
  gzFile  zipFileIn, zipFileLigandList;
  
  char    buffer [LENGTHLINE + 1];
  String* data = new String ();

  if (isGZFile) {
    zipFileIn = gzopen (this->filenameBindingProfile->Out(), "rb9");
    if (!zipFileIn) return false;
  }
  else {
    fileIn.open (this->filenameBindingProfile->Out(), fstream::in);
    if (!fileIn.is_open()) return false;
  }

  while (!((isGZFile)?gzeof(zipFileIn):fileIn.eof())) {
    
    if (isGZFile) gzgets(zipFileIn, buffer, LENGTHLINE);
    else          fileIn.getline(buffer, LENGTHLINE);
    
    if (!strlen(buffer)) continue;
    
    if (buffer[0] == '>') {
      
      if (data->Length()) {
        
        BindingInfo* newBindingInfo = new BindingInfo ();

        if (newBindingInfo->ReadFromString(data)) 
          this->bindingProfiles->Add(newBindingInfo);
        else 
          delete newBindingInfo;
        
      }
      
      data->In("");
      
    }
    
    data->Add(buffer);
    data->Add("\n");
    
  }
  
  if (isGZFile) gzclose(zipFileIn);
  else          fileIn.close();

  if (data) delete data;

  if (isGZFileLigandList) {
    zipFileLigandList = gzopen (this->filenameListLigands->Out(), "rb9");
    if (!zipFileLigandList) return false;
  }
  else {
    fileLigandList.open (this->filenameListLigands->Out(), fstream::in);
    if (!fileLigandList.is_open()) return false;
  }

  while (!((isGZFileLigandList)?gzeof(zipFileLigandList):fileLigandList.eof())) {
    
    if (isGZFileLigandList) gzgets(zipFileLigandList, buffer, LENGTHLINE);
    else                    fileLigandList.getline(buffer, LENGTHLINE);
    
    if (!strlen(buffer)) continue;
    
    if (strlen(buffer)) this->ligands->Add(new String (buffer));
    
  }
  
  if (isGZFileLigandList) gzclose(zipFileLigandList);
  else                    fileLigandList.close();

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::LoadBindingProfile (void) {

  if (!this->filenameBindingProfile || !this->filenameBindingProfile->Length() || !this->bindingProfiles)
    return false;

  this->bindingProfiles->Clear();
  
  bool isGZFile           = (this->filenameBindingProfile->Contain("gz"))?1:0;

  fstream fileIn;
  gzFile  zipFileIn;
  
  char    buffer [LENGTHLINE + 1];
  String* data = new String ();

  if (isGZFile) {
    zipFileIn = gzopen (this->filenameBindingProfile->Out(), "rb9");
    if (!zipFileIn) return false;
  }
  else {
    fileIn.open (this->filenameBindingProfile->Out(), fstream::in);
    if (!fileIn.is_open()) return false;
  }

  while (!((isGZFile)?gzeof(zipFileIn):fileIn.eof())) {
    
    if (isGZFile) gzgets(zipFileIn, buffer, LENGTHLINE);
    else          fileIn.getline(buffer, LENGTHLINE);
    
    if (!strlen(buffer)) continue;
    
    if (buffer[0] == '>') {
      
      if (data->Length()) {
        
        BindingInfo* newBindingInfo = new BindingInfo ();

        if (newBindingInfo->ReadFromString(data)) 
          this->bindingProfiles->Add(newBindingInfo);
        else 
          delete newBindingInfo;
        
      }
      
      data->In("");
      
    }
    
    data->Add(buffer);
    data->Add("\n");
    
  }
  
  if (data->Length()) {

    BindingInfo* newBindingInfo = new BindingInfo ();

    if (newBindingInfo->ReadFromString(data)) 
      this->bindingProfiles->Add(newBindingInfo);
    else 
      delete newBindingInfo;

  }

  if (isGZFile) gzclose(zipFileIn);
  else          fileIn.close();

  if (data) delete data;

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::HideEqualClassN (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length() || 
      !this->filenameOut     || !this->filenameOut->Length())
    return false;

  this->bindingProfiles->QuickSortListByArray(DomainSpace::AscendentDomainCode, NULL);
  
  int     previousClassNumber = -1;
  int     counter             = 0;
  
  bool    isGZFileOut         = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  for (long i = 0; i < this->bindingProfiles->Length(); i++) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->Get(i);
    int          currentClassNumber;
    
    sscanf(currentBindingInfo->CathCode()->Out(), "%d.%*s", &currentClassNumber);
    
    bool cond = (currentClassNumber == previousClassNumber);
    
    if (previousClassNumber == -1 || !cond) {
      
      if (currentBindingInfo->NearResiduesByLigand()->Length()) {
        counter++;
        if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
        else             fileOut << currentBindingInfo->ToString()->Out();
      }
      
    }
    
    previousClassNumber = currentClassNumber;
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::HideEqualArchitectureN (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length() || 
      !this->filenameOut     || !this->filenameOut->Length())
    return false;

  this->bindingProfiles->QuickSortListByArray(DomainSpace::AscendentDomainCode, NULL);
  
  int     previousClassNumber                 = -1;
  int     previousArchitectureNumber          = -1;
  int     counter                             = 0;
  
  bool    isGZFileOut                         = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  
  for (long i = 0; i < this->bindingProfiles->Length(); i++) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->Get(i);
    
    int          currentClassNumber;
    int          currentArchitectureNumber;
    
    sscanf(currentBindingInfo->CathCode()->Out(), "%d.%d.%*s",  &currentClassNumber, 
                                                                &currentArchitectureNumber);
    
    bool cond = (currentClassNumber                 == previousClassNumber)        && 
                (currentArchitectureNumber          == previousArchitectureNumber);
    
    if (previousClassNumber == -1 || !cond) {
      
      if (currentBindingInfo->NearResiduesByLigand()->Length()) {
        counter++;
        if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
        else             fileOut << currentBindingInfo->ToString()->Out();
      }
      
    }
    
    previousClassNumber                 = currentClassNumber;
    previousArchitectureNumber          = currentArchitectureNumber;
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::HideEqualTopologyN (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length() || 
      !this->filenameOut     || !this->filenameOut->Length())
    return false;

  this->bindingProfiles->QuickSortListByArray(DomainSpace::AscendentDomainCode, NULL);
  
  int     previousClassNumber                 = -1;
  int     previousArchitectureNumber          = -1;
  int     previousTopologyNumber              = -1;
  int     counter                             = 0;
  
  bool    isGZFileOut                         = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  
  for (long i = 0; i < this->bindingProfiles->Length(); i++) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->Get(i);
    
    int          currentClassNumber;
    int          currentArchitectureNumber;
    int          currentTopologyNumber;
    
    sscanf(currentBindingInfo->CathCode()->Out(), "%d.%d.%d.%*s", &currentClassNumber, 
                                                                  &currentArchitectureNumber,
                                                                  &currentTopologyNumber);
    
    bool cond = (currentClassNumber                 == previousClassNumber)                 && 
                (currentArchitectureNumber          == previousArchitectureNumber)          &&
                (currentTopologyNumber              == previousTopologyNumber);
    
    if (previousClassNumber == -1 || !cond) {
      
      if (currentBindingInfo->NearResiduesByLigand()->Length()) {
        counter++;
        if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
        else             fileOut << currentBindingInfo->ToString()->Out();
      }
      
    }
    
    previousClassNumber                 = currentClassNumber;
    previousArchitectureNumber          = currentArchitectureNumber;
    previousTopologyNumber              = currentTopologyNumber;
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::HideEqualHomologousSuperFamilyN (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length() || 
      !this->filenameOut     || !this->filenameOut->Length())
    return false;

  this->bindingProfiles->QuickSortListByArray(DomainSpace::AscendentDomainCode, NULL);
  
  int     previousClassNumber                 = -1;
  int     previousArchitectureNumber          = -1;
  int     previousTopologyNumber              = -1;
  int     previousHomologousSuperFamilyNumber = -1;
  int     counter                             = 0;
  
  bool    isGZFileOut                         = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  
  for (long i = 0; i < this->bindingProfiles->Length(); i++) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->Get(i);
    
    int          currentClassNumber;
    int          currentArchitectureNumber;
    int          currentTopologyNumber;
    int          currentHomologousSuperFamilyNumber;
    
    sscanf(currentBindingInfo->CathCode()->Out(), "%d.%d.%d.%d.%*s",  &currentClassNumber, 
                                                                      &currentArchitectureNumber,
                                                                      &currentTopologyNumber,
                                                                      &currentHomologousSuperFamilyNumber);
    
    bool cond = (currentClassNumber                 == previousClassNumber)                 && 
                (currentArchitectureNumber          == previousArchitectureNumber)          &&
                (currentTopologyNumber              == previousTopologyNumber)              &&
                (currentHomologousSuperFamilyNumber == previousHomologousSuperFamilyNumber);
    
    if (previousClassNumber == -1 || !cond) {
      
      if (currentBindingInfo->NearResiduesByLigand()->Length()) {
        counter++;
        if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
        else             fileOut << currentBindingInfo->ToString()->Out();
      }
      
    }
    
    previousClassNumber                 = currentClassNumber;
    previousArchitectureNumber          = currentArchitectureNumber;
    previousTopologyNumber              = currentTopologyNumber;
    previousHomologousSuperFamilyNumber = currentHomologousSuperFamilyNumber;
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::HideEqualSimilar35PercentN (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length() || 
      !this->filenameOut     || !this->filenameOut->Length())
    return false;

  this->bindingProfiles->QuickSortListByArray(DomainSpace::AscendentDomainCode, NULL);
  
  int     previousClassNumber                 = -1;
  int     previousArchitectureNumber          = -1;
  int     previousTopologyNumber              = -1;
  int     previousHomologousSuperFamilyNumber = -1;
  int     previousSimilar35Number             = -1;
  int     counter                             = 0;
  
  bool    isGZFileOut                         = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  
  for (long i = 0; i < this->bindingProfiles->Length(); i++) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->Get(i);
    
    int          currentClassNumber;
    int          currentArchitectureNumber;
    int          currentTopologyNumber;
    int          currentHomologousSuperFamilyNumber;
    int          currentSimilar35Number;
    
    sscanf(currentBindingInfo->CathCode()->Out(), "%d.%d.%d.%d.%d.%*s", &currentClassNumber, 
                                                                        &currentArchitectureNumber,
                                                                        &currentTopologyNumber,
                                                                        &currentHomologousSuperFamilyNumber,
                                                                        &currentSimilar35Number);
    
    bool cond = (currentClassNumber                 == previousClassNumber)                 && 
                (currentArchitectureNumber          == previousArchitectureNumber)          &&
                (currentTopologyNumber              == previousTopologyNumber)              &&
                (currentHomologousSuperFamilyNumber == previousHomologousSuperFamilyNumber) &&
                (currentSimilar35Number             == previousSimilar35Number);
    
    if (previousClassNumber == -1 || !cond) {
      
      if (currentBindingInfo->NearResiduesByLigand()->Length()) {
        counter++;
        if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
        else             fileOut << currentBindingInfo->ToString()->Out();
      }
      
    }
    
    previousClassNumber                 = currentClassNumber;
    previousArchitectureNumber          = currentArchitectureNumber;
    previousTopologyNumber              = currentTopologyNumber;
    previousHomologousSuperFamilyNumber = currentHomologousSuperFamilyNumber;
    previousSimilar35Number             = currentSimilar35Number;
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::HideEqualHomologous60PercentN (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length() || 
      !this->filenameOut     || !this->filenameOut->Length())
    return false;

  this->bindingProfiles->QuickSortListByArray(DomainSpace::AscendentDomainCode, NULL);
  
  int     previousClassNumber                 = -1;
  int     previousArchitectureNumber          = -1;
  int     previousTopologyNumber              = -1;
  int     previousHomologousSuperFamilyNumber = -1;
  int     previousSimilar35Number             = -1;
  int     previousHomologous60Number          = -1;
  int     counter                             = 0;
  
  bool    isGZFileOut                         = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  
  for (long i = 0; i < this->bindingProfiles->Length(); i++) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->Get(i);
    
    int          currentClassNumber;
    int          currentArchitectureNumber;
    int          currentTopologyNumber;
    int          currentHomologousSuperFamilyNumber;
    int          currentSimilar35Number;
    int          currentHomologous60Number;
    
    sscanf(currentBindingInfo->CathCode()->Out(), "%d.%d.%d.%d.%d.%d.%*s",  &currentClassNumber, 
                                                                            &currentArchitectureNumber,
                                                                            &currentTopologyNumber,
                                                                            &currentHomologousSuperFamilyNumber,
                                                                            &currentSimilar35Number,
                                                                            &currentHomologous60Number);
    
    bool cond = (currentClassNumber                 == previousClassNumber)                 && 
                (currentArchitectureNumber          == previousArchitectureNumber)          &&
                (currentTopologyNumber              == previousTopologyNumber)              &&
                (currentHomologousSuperFamilyNumber == previousHomologousSuperFamilyNumber) &&
                (currentSimilar35Number             == previousSimilar35Number)             &&
                (currentHomologous60Number          == previousHomologous60Number);
    
    if (previousClassNumber == -1 || !cond) {
      
      if (currentBindingInfo->NearResiduesByLigand()->Length()) {
        counter++;
        if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
        else             fileOut << currentBindingInfo->ToString()->Out();
      }
      
    }
    
    previousClassNumber                 = currentClassNumber;
    previousArchitectureNumber          = currentArchitectureNumber;
    previousTopologyNumber              = currentTopologyNumber;
    previousHomologousSuperFamilyNumber = currentHomologousSuperFamilyNumber;
    previousSimilar35Number             = currentSimilar35Number;
    previousHomologous60Number          = currentHomologous60Number;
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::HideEqualLike90PercentN (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length() || 
      !this->filenameOut     || !this->filenameOut->Length())
    return false;

  this->bindingProfiles->QuickSortListByArray(DomainSpace::AscendentDomainCode, NULL);
  
  int     previousClassNumber                 = -1;
  int     previousArchitectureNumber          = -1;
  int     previousTopologyNumber              = -1;
  int     previousHomologousSuperFamilyNumber = -1;
  int     previousSimilar35Number             = -1;
  int     previousHomologous60Number          = -1;
  int     previousLike90Number                = -1;
  int     counter                             = 0;
  
  bool    isGZFileOut                         = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  
  for (long i = 0; i < this->bindingProfiles->Length(); i++) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->Get(i);
    
    int          currentClassNumber;
    int          currentArchitectureNumber;
    int          currentTopologyNumber;
    int          currentHomologousSuperFamilyNumber;
    int          currentSimilar35Number;
    int          currentHomologous60Number;
    int          currentLike90Number;
    
    sscanf(currentBindingInfo->CathCode()->Out(), "%d.%d.%d.%d.%d.%d.%d.%*s",  &currentClassNumber, 
                                                                               &currentArchitectureNumber,
                                                                               &currentTopologyNumber,
                                                                               &currentHomologousSuperFamilyNumber,
                                                                               &currentSimilar35Number,
                                                                               &currentHomologous60Number,
                                                                               &currentLike90Number);
    
    bool cond = (currentClassNumber                 == previousClassNumber)                 && 
                (currentArchitectureNumber          == previousArchitectureNumber)          &&
                (currentTopologyNumber              == previousTopologyNumber)              &&
                (currentHomologousSuperFamilyNumber == previousHomologousSuperFamilyNumber) &&
                (currentSimilar35Number             == previousSimilar35Number)             &&
                (currentHomologous60Number          == previousHomologous60Number)          &&
                (currentLike90Number                == previousLike90Number);
    
    if (previousClassNumber == -1 || !cond) {
      
      if (currentBindingInfo->NearResiduesByLigand()->Length()) {
        counter++;
        if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
        else             fileOut << currentBindingInfo->ToString()->Out();
      }
      
    }
    
    previousClassNumber                 = currentClassNumber;
    previousArchitectureNumber          = currentArchitectureNumber;
    previousTopologyNumber              = currentTopologyNumber;
    previousHomologousSuperFamilyNumber = currentHomologousSuperFamilyNumber;
    previousSimilar35Number             = currentSimilar35Number;
    previousHomologous60Number          = currentHomologous60Number;
    previousLike90Number                = currentLike90Number;
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::HideEqualIdentical100PercentN (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length() || 
      !this->filenameOut     || !this->filenameOut->Length())
    return false;

  this->bindingProfiles->QuickSortListByArray(DomainSpace::AscendentDomainCode, NULL);
  
  int     previousClassNumber                 = -1;
  int     previousArchitectureNumber          = -1;
  int     previousTopologyNumber              = -1;
  int     previousHomologousSuperFamilyNumber = -1;
  int     previousSimilar35Number             = -1;
  int     previousHomologous60Number          = -1;
  int     previousLike90Number                = -1;
  int     previousIdentical100Number          = -1;
  int     counter                             = 0;
  
  bool    isGZFileOut                        = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  
  for (long i = 0; i < this->bindingProfiles->Length(); i++) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->Get(i);
    
    int          currentClassNumber;
    int          currentArchitectureNumber;
    int          currentTopologyNumber;
    int          currentHomologousSuperFamilyNumber;
    int          currentSimilar35Number;
    int          currentHomologous60Number;
    int          currentLike90Number;
    int          currentIdentical100Number;
    
    sscanf(currentBindingInfo->CathCode()->Out(), "%d.%d.%d.%d.%d.%d.%d.%d.%*s",  &currentClassNumber, 
                                                                                  &currentArchitectureNumber,
                                                                                  &currentTopologyNumber,
                                                                                  &currentHomologousSuperFamilyNumber,
                                                                                  &currentSimilar35Number,
                                                                                  &currentHomologous60Number,
                                                                                  &currentLike90Number,
                                                                                  &currentIdentical100Number);
    
    bool cond = (currentClassNumber                 == previousClassNumber)                 && 
                (currentArchitectureNumber          == previousArchitectureNumber)          &&
                (currentTopologyNumber              == previousTopologyNumber)              &&
                (currentHomologousSuperFamilyNumber == previousHomologousSuperFamilyNumber) &&
                (currentSimilar35Number             == previousSimilar35Number)             &&
                (currentHomologous60Number          == previousHomologous60Number)          &&
                (currentLike90Number                == previousLike90Number)                &&
                (currentIdentical100Number          == previousIdentical100Number);
    
    if (previousClassNumber == -1 || !cond) {
      
      if (currentBindingInfo->NearResiduesByLigand()->Length()) {
        counter++;
        if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
        else             fileOut << currentBindingInfo->ToString()->Out();
      }
      
    }
    
    previousClassNumber                 = currentClassNumber;
    previousArchitectureNumber          = currentArchitectureNumber;
    previousTopologyNumber              = currentTopologyNumber;
    previousHomologousSuperFamilyNumber = currentHomologousSuperFamilyNumber;
    previousSimilar35Number             = currentSimilar35Number;
    previousHomologous60Number          = currentHomologous60Number;
    previousLike90Number                = currentLike90Number;
    previousIdentical100Number          = currentIdentical100Number;
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::HideEqualDomainN (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length() || 
      !this->filenameOut     || !this->filenameOut->Length())
    return false;

  this->bindingProfiles->QuickSortListByArray(DomainSpace::AscendentDomainCode, NULL);
  
  int     previousClassNumber                 = -1;
  int     previousArchitectureNumber          = -1;
  int     previousTopologyNumber              = -1;
  int     previousHomologousSuperFamilyNumber = -1;
  int     previousSimilar35Number             = -1;
  int     previousHomologous60Number          = -1;
  int     previousLike90Number                = -1;
  int     previousIdentical100Number          = -1;
  int     previousDomainNumber                = -1;
  int     counter                             = 0;
  
  bool    isGZFileOut                        = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  
  for (long i = 0; i < this->bindingProfiles->Length(); i++) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->Get(i);
    
    int          currentClassNumber;
    int          currentArchitectureNumber;
    int          currentTopologyNumber;
    int          currentHomologousSuperFamilyNumber;
    int          currentSimilar35Number;
    int          currentHomologous60Number;
    int          currentLike90Number;
    int          currentIdentical100Number;
    int          currentDomainNumber;
    
    sscanf(currentBindingInfo->CathCode()->Out(), "%d.%d.%d.%d.%d.%d.%d.%d.%d.%*s",  &currentClassNumber, 
                                                                                     &currentArchitectureNumber,
                                                                                     &currentTopologyNumber,
                                                                                     &currentHomologousSuperFamilyNumber,
                                                                                     &currentSimilar35Number,
                                                                                     &currentHomologous60Number,
                                                                                     &currentLike90Number,
                                                                                     &currentIdentical100Number,
                                                                                     &currentDomainNumber);
    
    bool cond = (currentClassNumber                 == previousClassNumber)                 && 
                (currentArchitectureNumber          == previousArchitectureNumber)          &&
                (currentTopologyNumber              == previousTopologyNumber)              &&
                (currentHomologousSuperFamilyNumber == previousHomologousSuperFamilyNumber) &&
                (currentSimilar35Number             == previousSimilar35Number)             &&
                (currentHomologous60Number          == previousHomologous60Number)          &&
                (currentLike90Number                == previousLike90Number)                &&
                (currentIdentical100Number          == previousIdentical100Number)          &&
                (currentDomainNumber                == previousDomainNumber);
    
    if (previousClassNumber == -1 || !cond) {
      
      if (currentBindingInfo->NearResiduesByLigand()->Length()) {
        counter++;
        if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
        else             fileOut << currentBindingInfo->ToString()->Out();
      }
      
    }
    
    previousClassNumber                 = currentClassNumber;
    previousArchitectureNumber          = currentArchitectureNumber;
    previousTopologyNumber              = currentTopologyNumber;
    previousHomologousSuperFamilyNumber = currentHomologousSuperFamilyNumber;
    previousSimilar35Number             = currentSimilar35Number;
    previousHomologous60Number          = currentHomologous60Number;
    previousLike90Number                = currentLike90Number;
    previousIdentical100Number          = currentIdentical100Number;
    previousDomainNumber                = currentDomainNumber;
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::ExtractDomainComplexes (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length()) {
    if (!this->LoadData())                                          return false;
    if (!this->bindingProfiles || !this->bindingProfiles->Length()) return false;
  }
  
  if (!this->filenameOut || !this->filenameOut->Length()) return false;
  
  bool isGZFileOut = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  int counter = 0;
  
  this->bindingProfiles->SetInitial();
  while (this->bindingProfiles->SetNext()) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->GetCurrent();
    
    if (currentBindingInfo->NearResiduesByLigand()->Length()) {
      counter++;
      if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
      else             fileOut << currentBindingInfo->ToString()->Out();
    }
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::ExtractDomainComplexInterIntraDomainBinding (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length()) {
    if (!this->LoadData())                                          return false;
    if (!this->bindingProfiles || !this->bindingProfiles->Length()) return false;
  }
  
  if (!this->filenameOut || !this->filenameOut->Length()) return false;
  
  char filenameOutInter    [LENGTHTEXT], filenameOutIntra    [LENGTHTEXT];
  char filenameLigandInter [LENGTHTEXT], filenameLigandIntra [LENGTHTEXT];
  char filenamePDBInter    [LENGTHTEXT], filenamePDBIntra    [LENGTHTEXT];
  
  sprintf(filenameOutInter, "InterDomain.%s\0", this->filenameOut->Out());
  sprintf(filenameOutIntra, "IntraDomain.%s\0", this->filenameOut->Out());
  
  sprintf(filenameLigandInter, "InterLigands.%s\0", this->filenameOut->Out());
  sprintf(filenameLigandIntra, "IntraLigands.%s\0", this->filenameOut->Out());
  
  sprintf(filenamePDBInter, "InterPDB.%s\0", this->filenameOut->Out());
  sprintf(filenamePDBIntra, "IntraPDB.%s\0", this->filenameOut->Out());
  
  bool    isGZFileOut = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOutInter,        fileOutIntra;
  fstream fileListLigandInter, fileListLigandIntra;
  fstream fileListPDBInter,    fileListPDBIntra;
  
  gzFile  zipFileOutInter, zipFileOutIntra;
  
  int     counterInterPDB    = 0, counterIntraPDB    = 0;
  int     counterInterData   = 0, counterIntraData   = 0;
  
  if (isGZFileOut) {
    
    zipFileOutInter = gzopen (filenameOutInter, "wb9");
    if (!zipFileOutInter) return false;
    
    zipFileOutIntra = gzopen (filenameOutIntra, "wb9");
    if (!zipFileOutIntra) return false;
    
  }
  else {
    
    fileOutInter.open (filenameOutInter, fstream::out);
    if (!fileOutInter.is_open()) return false;
    
    fileOutIntra.open (filenameOutIntra, fstream::out);
    if (!fileOutIntra.is_open()) return false;
    
  }
  
  fileListLigandInter.open (filenameLigandInter, fstream::out);
  if (!fileListLigandInter.is_open()) return false;
  
  fileListLigandIntra.open (filenameLigandIntra, fstream::out);
  if (!fileListLigandIntra.is_open()) return false;

  fileListPDBInter.open (filenamePDBInter, fstream::out);
  if (!fileListPDBInter.is_open()) return false;
  
  fileListPDBIntra.open (filenamePDBIntra, fstream::out);
  if (!fileListPDBIntra.is_open()) return false;

  TListE <String>* pdbChainList         = new TListE <String> ();
  
  TListE <String>* ligandListInter = new TListE <String> ();
  TListE <String>* ligandListIntra = new TListE <String> ();
  
  this->bindingProfiles->SetInitial();
  while (this->bindingProfiles->SetNext()) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->GetCurrent();
    
    String* searchSamePDBCode = pdbChainList->FirstOcurrence(DomainSpace::EqualPDBChain, currentBindingInfo->Domain());
    
    if (!searchSamePDBCode) {
      char newPDB [6];
      strncpy(newPDB, currentBindingInfo->Domain()->Out(), 5);
      pdbChainList->Add(new String (newPDB));
    }
    
  }
  
  if (!pdbChainList->Length()) return false;
  
  cout << "Number of PDB chain " << pdbChainList->Length() << endl;
  
  int counterSteps = 0;
  
  pdbChainList->SetInitial();
  while (pdbChainList->SetNext()) {
    
    String*               currentPDBChain    = pdbChainList->GetCurrent();
    TListE <BindingInfo>* domainSamePDBChain = new TListE <BindingInfo> ();
    
    cout << ++counterSteps << " - Domain: " << currentPDBChain->Out() << endl;
    
    this->bindingProfiles->AllOcurrence(DomainSpace::DomainFromPDB, domainSamePDBChain, currentPDBChain);
    
    if (!domainSamePDBChain->Length()) {
      
      if (domainSamePDBChain) delete domainSamePDBChain;
      if (pdbChainList)       delete pdbChainList;
      if (ligandListInter)    delete ligandListInter;
      if (ligandListIntra)    delete ligandListIntra;
      
      return false;
      
    }
    
    //IntraDomain
    if (domainSamePDBChain->Length() == 1) {

      counterIntraData++;
      if (isGZFileOut) gzprintf(zipFileOutIntra, "%s\0", domainSamePDBChain->GetFirst()->ToString()->Out());
      else             fileOutIntra << domainSamePDBChain->GetFirst()->ToString()->Out();

      domainSamePDBChain->GetFirst()->NearResiduesByLigand()->SetInitial();
      while (domainSamePDBChain->GetFirst()->NearResiduesByLigand()->SetNext()) {
        
        String* searchSameLigand = ligandListIntra->FirstOcurrence(DomainSpace::SameLigand, domainSamePDBChain->GetFirst()->NearResiduesByLigand()->GetCurrent()->LigandName());
        
        if (!searchSameLigand)
          ligandListIntra->Add(new String (domainSamePDBChain->GetFirst()->NearResiduesByLigand()->GetCurrent()->LigandName()));
        
      }

      counterIntraPDB++;
      fileListPDBIntra << currentPDBChain->Out() << endl;

    }
    else {

      TListE <LigandDomainNumber>* ligandsInPDBInter = new TListE <LigandDomainNumber> ();
      TListE <LigandDomainNumber>* ligandsInPDBIntra = new TListE <LigandDomainNumber> ();

      for (int i = 0; i < domainSamePDBChain->Length(); i++) {
        
        domainSamePDBChain->Get(i)->NearResiduesByLigand()->SetInitial();
        while (domainSamePDBChain->Get(i)->NearResiduesByLigand()->SetNext()) {
          
          LigandNearResidues* currentLigand      = domainSamePDBChain->Get(i)->NearResiduesByLigand()->GetCurrent();
          int                 positionLigandName = ligandsInPDBIntra->FirstOcurrencePosition(DomainSpace::EqualLigand, currentLigand);
          
          if (positionLigandName == -1) {
            ligandsInPDBIntra->Add(new LigandDomainNumber (currentLigand->LigandName(), currentLigand->LigandNumber()));
            ligandsInPDBInter->Add(new LigandDomainNumber (currentLigand->LigandName(), currentLigand->LigandNumber()));
          }
          else {
            ligandsInPDBIntra->GetNode(positionLigandName)->SetHidden();
            ligandsInPDBInter->GetNode(positionLigandName)->SetHidden();
          }
          
        }
        
      }
    
      ligandsInPDBInter->SetInitial();
      while (ligandsInPDBInter->SetNext()) {
        
        if (ligandsInPDBInter->GetCurrentNode()->IsHidden())  
          ligandsInPDBInter->GetCurrentNode()->SetVisible();
        else if (ligandsInPDBInter->GetCurrentNode()->IsVisible()) 
          ligandsInPDBInter->GetCurrentNode()->SetHidden();
        
      }

      for (int i = 0; i < domainSamePDBChain->Length(); i++) {
        
        BindingInfo* currentBindingInfo = domainSamePDBChain->Get(i);
        
        //IntraDomain
        if (currentBindingInfo->HasAtLeastOneLigandInList(ligandsInPDBIntra)) {
          
          counterIntraData++;
          if (isGZFileOut) gzprintf(zipFileOutIntra, "%s\0", currentBindingInfo->ToStringForLigands(ligandsInPDBIntra)->Out());
          else             fileOutIntra << currentBindingInfo->ToStringForLigands(ligandsInPDBIntra)->Out();

          currentBindingInfo->NearResiduesByLigand()->SetInitial();
          while (currentBindingInfo->NearResiduesByLigand()->SetNext()) {

            String* searchSameLigand = ligandListIntra->FirstOcurrence(DomainSpace::SameLigand, currentBindingInfo->NearResiduesByLigand()->GetCurrent()->LigandName());

            if (!searchSameLigand)
              ligandListIntra->Add(new String (currentBindingInfo->NearResiduesByLigand()->GetCurrent()->LigandName()));

          }

          counterIntraPDB++;
          fileListPDBIntra << currentPDBChain->Out() << endl;
          
        }
        
        //InterDomain
        if (currentBindingInfo->HasAtLeastOneLigandInList(ligandsInPDBInter)) {
          
          counterInterData++;
          if (isGZFileOut) gzprintf(zipFileOutInter, "%s\0", currentBindingInfo->ToStringForLigands(ligandsInPDBInter)->Out());
          else             fileOutInter << currentBindingInfo->ToStringForLigands(ligandsInPDBInter)->Out();

          currentBindingInfo->NearResiduesByLigand()->SetInitial();
          while (currentBindingInfo->NearResiduesByLigand()->SetNext()) {

            String* searchSameLigand = ligandListInter->FirstOcurrence(DomainSpace::SameLigand, currentBindingInfo->NearResiduesByLigand()->GetCurrent()->LigandName());

            if (!searchSameLigand)
              ligandListInter->Add(new String (currentBindingInfo->NearResiduesByLigand()->GetCurrent()->LigandName()));

          }

          counterInterPDB++;
          fileListPDBInter << currentPDBChain->Out() << endl;
          
        }
        
      }

      if (ligandsInPDBInter) delete ligandsInPDBInter;
      if (ligandsInPDBIntra) delete ligandsInPDBIntra;

    }
    
    domainSamePDBChain->TransferAll();
    
    if (domainSamePDBChain) delete domainSamePDBChain;
    
  }
  
  ligandListIntra->SetInitial();
  while (ligandListIntra->SetNext()) 
    fileListLigandIntra << ligandListIntra->GetCurrent()->Out() << endl;
  
  ligandListInter->SetInitial();
  while (ligandListInter->SetNext()) 
    fileListLigandInter << ligandListInter->GetCurrent()->Out() << endl;
  
  if (pdbChainList) delete pdbChainList;
  
  if (isGZFileOut) { gzclose(zipFileOutInter); gzclose(zipFileOutIntra); }
  else             { fileOutInter.close();     fileOutIntra.close(); }
  
  fileListLigandInter.close(); fileListLigandIntra.close();
  fileListPDBInter.close();    fileListPDBIntra.close();
  
  char tmpFilename [LENGTHTEXT];
  
  sprintf(tmpFilename, "%d.%s\0", counterInterData, filenameOutInter);
  link(filenameOutInter, tmpFilename); unlink(filenameOutInter);
  
  sprintf(tmpFilename, "%d.%s\0", counterIntraData, filenameOutIntra);
  link(filenameOutIntra, tmpFilename); unlink(filenameOutIntra);
  
  sprintf(tmpFilename, "%d.%s\0", counterInterPDB, filenamePDBInter);
  link(filenamePDBInter, tmpFilename); unlink(filenamePDBInter);
  
  sprintf(tmpFilename, "%d.%s\0", counterIntraPDB, filenamePDBIntra);
  link(filenamePDBIntra, tmpFilename); unlink(filenamePDBIntra);
  
  sprintf(tmpFilename, "%ld.%s\0", ligandListInter->Length(), filenameLigandInter);
  link(filenameLigandInter, tmpFilename); unlink(filenameLigandInter);
  
  sprintf(tmpFilename, "%ld.%s\0", ligandListIntra->Length(), filenameLigandIntra);
  link(filenameLigandIntra, tmpFilename); unlink(filenameLigandIntra);
  
  if (ligandListInter) delete ligandListInter;
  if (ligandListIntra) delete ligandListIntra;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::SplitDataInFilesByLigands (void) {
  
  if (!this->bindingProfiles   || !this->bindingProfiles->Length()) {
    if (!this->LoadData())                                          return false;
    if (!this->bindingProfiles || !this->bindingProfiles->Length()) return false;
  }
  
  if (!this->filenameOut || !this->filenameOut->Length()) return false;
  
  TListE <LigandDomainNumber>* listLigandFreq = new TListE <LigandDomainNumber> ();
  int                          counterLigand  = 0;
  
  char                         filenameDataByLigand [LENGTHTEXT];
  fstream                      fileDataByLigand;
  
  this->ligands->SetInitial();
  while (this->ligands->SetNext()) {
    
    String*             currentLigand = this->ligands->GetCurrent();
    LigandDomainNumber* ligandFreq    = new LigandDomainNumber (currentLigand, 0);
    
    cout << ++counterLigand << " - " << currentLigand->Out() << endl;
    
    listLigandFreq->Add(ligandFreq);
    
    sprintf(filenameDataByLigand, "%s.%s\0", currentLigand->Out(), this->filenameOut->Out());
    
    fileDataByLigand.open(filenameDataByLigand, fstream::out);
    
    this->bindingProfiles->SetInitial();
    while (this->bindingProfiles->SetNext()) 
      if (this->bindingProfiles->GetCurrent()->HasALigandName(ligandFreq)) {
        ligandFreq->number++;
        fileDataByLigand << this->bindingProfiles->GetCurrent()->ToStringForLigand(ligandFreq)->Out();
      }
    
    fileDataByLigand.close();
    
  }
  
  listLigandFreq->QuickSortListByArray(DomainSpace::DescendentFreqLigand, NULL);
  
  sprintf(filenameDataByLigand, "ListFrequencies.%s\0", this->filenameOut->Out());
  fileDataByLigand.open(filenameDataByLigand, fstream::out);
  
  listLigandFreq->SetInitial();
  while (listLigandFreq->SetNext())
    fileDataByLigand << listLigandFreq->GetCurrent()->name->Out() << " " << listLigandFreq->GetCurrent()->number << endl;
  
  fileDataByLigand.close();
  
  if (listLigandFreq) delete listLigandFreq;

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::SplitDataInTwoFiles (String* filenameOut1, String* filenameOut2, float percentage) {
  
  if (!filenameOut1          || !filenameOut1->Length()           || 
      !filenameOut2          || !filenameOut2->Length()           || 
      !this->bindingProfiles || !this->bindingProfiles->Length())
      return false;
    
  vector <int> randomFlag;
  
  for (int i = 0; i < this->bindingProfiles->Length(); ++i) randomFlag.push_back(i);
  for (int i = 0; i < ITERATIONS; i++)                      random_shuffle(randomFlag.begin(), randomFlag.end());
  
  int numberBeforeDiv   = this->bindingProfiles->Length()*percentage/100;
  
  bool isGZFileOut1     = (filenameOut1->Contain("gz"))?1:0;
  bool isGZFileOut2     = (filenameOut2->Contain("gz"))?1:0;

  fstream fileOut1,    fileOut2;
  gzFile  zipFileOut1, zipFileOut2;
  
  if (isGZFileOut1) {
    zipFileOut1 = gzopen (filenameOut1->Out(), "wb9");
    if (!zipFileOut1)        return false;
  }
  else {
    fileOut1.open (filenameOut1->Out(), fstream::out);
    if (!fileOut1.is_open()) return false;
  }
  
  if (isGZFileOut2) {
    zipFileOut2 = gzopen (filenameOut2->Out(), "wb9");
    if (!zipFileOut2)        return false;
  }
  else {
    fileOut2.open (filenameOut2->Out(), fstream::out);
    if (!fileOut2.is_open()) return false;
  }
  
  for (int i = 0; i < this->bindingProfiles->Length(); i++) {
      
    if (this->bindingProfiles->GetNode(randomFlag.at(i))->IsHidden()) continue;
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->Get(randomFlag.at(i));
    
    if (i <= numberBeforeDiv) {
      if (isGZFileOut1) gzprintf(zipFileOut1, "%s\0", currentBindingInfo->ToString()->Out());
      else              fileOut1 << currentBindingInfo->ToString()->Out();
    }
    else {
      if (isGZFileOut2) gzprintf(zipFileOut2, "%s\0", currentBindingInfo->ToString()->Out());
      else              fileOut2 << currentBindingInfo->ToString()->Out();
    }
    
  }
  
  if (isGZFileOut1) gzclose(zipFileOut1);
  else              fileOut1.close();
  
  if (isGZFileOut2) gzclose(zipFileOut2);
  else              fileOut2.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::FilterChangedResiduesAsLigandHetAtm (void) {
  
  if (!this->bindingProfiles || !this->bindingProfiles->Length()) {
    if (!this->LoadData())                                          return false;
    if (!this->bindingProfiles || !this->bindingProfiles->Length()) return false;
  }
  
  if (!this->filenameOut || !this->filenameOut->Length()) return false;
  
  bool             isGZFileOut       = (this->filenameOut->Contain("gz"))?1:0;

  fstream          fileOut, fileExclusion;
  gzFile           zipFileOut, zipFileExclusion;
  
  int              counter           = 0;
  TListE <String>* exclusionList     = new TListE <String> ();
  
  char             filenameExclusionList [LENGTHTEXT];
  sprintf(filenameExclusionList, "%s.exclusion\0", this->filenameListLigands->Out());
  
  bool             isGZFileExclusion = (strstr(filenameExclusionList, "gz"))?1:0;
  
  this->bindingProfiles->SetInitial();
  while (this->bindingProfiles->SetNext()) 
    this->bindingProfiles->GetCurrent()->DeleteResiduesAppearAsLigand(exclusionList);
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  if (isGZFileExclusion) {
    zipFileExclusion = gzopen (filenameExclusionList, "wb9");
    if (!zipFileExclusion) return false;
  }
  else {
    fileExclusion.open (filenameExclusionList, fstream::out);
    if (!fileExclusion.is_open()) return false;
  }
  
  this->bindingProfiles->SetInitial();
  while (this->bindingProfiles->SetNext()) {
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->GetCurrent();
    
    currentBindingInfo->DeleteLigandsAppearInList(exclusionList);
    
    if (currentBindingInfo->NearResiduesByLigand()->Length()) {
      counter++;
      if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
      else             fileOut << currentBindingInfo->ToString()->Out();
    }
    
  }
  
  exclusionList->SetInitial();
  while (exclusionList->SetNext()) {
    String* currentLigand = exclusionList->GetCurrent();
    if (isGZFileExclusion) gzprintf(zipFileExclusion, "%s\n", currentLigand->Out());
    else                   fileExclusion << currentLigand->Out() << endl;
  }
  
  if (exclusionList) delete exclusionList;
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  if (isGZFileExclusion) gzclose(zipFileExclusion);
  else                   fileExclusion.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessBindingFASTAProfile::WriteBindingProfileFile (void) {
  
  if (!this->filenameOut || !this->filenameOut->Length()) return false;
  
  bool isGZFileOut = (this->filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (this->filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (this->filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  int counter = 0;
  
  this->bindingProfiles->SetInitial();
  while (this->bindingProfiles->SetNext()) {
    
    if (this->bindingProfiles->GetCurrentNode()->IsHidden()) continue;
    
    BindingInfo* currentBindingInfo = this->bindingProfiles->GetCurrent();
    
    if (currentBindingInfo->NearResiduesByLigand()->Length()) {
      counter++;
      if (isGZFileOut) gzprintf(zipFileOut, "%s\0", currentBindingInfo->ToString()->Out());
      else             fileOut << currentBindingInfo->ToString()->Out();
    }
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  char finalFilenameOut [LENGTHTEXT];
  sprintf(finalFilenameOut, "%d.%s\0", counter, this->filenameOut->Out());
  
  link(this->filenameOut->Out(), finalFilenameOut);
  unlink(this->filenameOut->Out());
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessBindingFASTAProfile ProcessBindingFASTAProfile::operator= (const ProcessBindingFASTAProfile& processBindingFASTAProfile) {
  
  this->filenameBindingProfile->In(processBindingFASTAProfile.filenameBindingProfile);
  this->filenameListLigands->In(processBindingFASTAProfile.filenameListLigands);
  this->filenameOut->In(processBindingFASTAProfile.filenameOut);

  *(this->bindingProfiles) = *(processBindingFASTAProfile.bindingProfiles);   
  *(this->ligands)         = *(processBindingFASTAProfile.ligands);
  
  return *this;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
